package com.campusevaluation.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.campusevaluation.common.exception.Result;
import com.campusevaluation.common.exception.UnauthorizedException;
import com.campusevaluation.common.utils.FormatUtil;
import com.campusevaluation.common.utils.UserContext;
import com.campusevaluation.config.JwtProperties;
import com.campusevaluation.domain.dto.LoginDTO;
import com.campusevaluation.domain.dto.UserDTO;
import com.campusevaluation.domain.po.Department;
import com.campusevaluation.domain.po.User;
import com.campusevaluation.domain.vo.UserVO;
import com.campusevaluation.dao.mapper.UserMapper;
import com.campusevaluation.service.IDepartmentService;
import com.campusevaluation.service.IUserService;
import com.campusevaluation.utils.AliOssUtil;
import com.campusevaluation.utils.EmailUtil;
import com.campusevaluation.utils.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;

@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements IUserService {
    private final static String SALT = "chxy";
    private static final String REGEX =
            "^(?:(?=.*[0-9])(?=.*[a-zA-Z])|(?=.*[0-9])(?=.*[^\\w\\s])|(?=.*[a-zA-Z])(?=.*[^\\w\\s])).+$";
    private final JwtUtil jwtUtil;
    private final JwtProperties jwtProperties;
    private final EmailUtil emailUtil;
    private final IDepartmentService departmentService;
    private final AliOssUtil aliOssUtil;

    /**
     * 登录
     * @param loginDTO
     * @return
     */
    @Override
    public Result<Map<String, Object>> login(LoginDTO loginDTO) {
        if (StringUtils.isBlank(loginDTO.getUsername())) {
            return Result.error("用户名不存在", 404);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", loginDTO.getUsername());
        User user = this.getOne(queryWrapper);
        if (user == null) {
            return Result.error("用户名不存在", 404);
        }
        String password = DigestUtils.md5DigestAsHex((SALT + loginDTO.getPassword()).getBytes());
        if (!user.getPassword().equals(password)) {
            return Result.error("用户名或密码错误", 404);
        }
        Department department = departmentService.getById(user.getDepartmentId());
        String token = jwtUtil.createToken(user.getId(), jwtProperties.getTokenTTL());
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("id", user.getId());
        // 检查是否第一次登录
        map.put("role", user.getRole());
        // 检查该部门是否被删除
        map.put("departmentId", department == null ? -1 : department.getId());
        return Result.success("登录成功", map);
    }

    /**
     * 发送验证码
     * @param registerDTO
     * @return
     */
    public Result<String> sendVerificationCode(UserDTO registerDTO) {
        if (!FormatUtil.isEmail(registerDTO.getEmail())) {
            return Result.error("邮箱格式错误");
        }
        emailUtil.saveCode(registerDTO.getEmail());
        try {
            emailUtil.sendVerificationCode(registerDTO.getEmail());
        } catch (Exception e) {
            throw new UnauthorizedException("邮箱发送失败");
        }
        return Result.success(null, "验证码发送成功");
    }

    /**
     * 注册
     * @param registerDTO
     * @return
     */
    @Transactional
    public Result<String> register(UserDTO registerDTO) {
        if (StringUtils.isBlank(registerDTO.getUsername())) {
            return Result.error("用户名为空", 404);
        }
        if (!FormatUtil.isEmail(registerDTO.getEmail())) {
            return Result.error("邮箱格式错误");
        }
        if (query().eq("email", registerDTO.getEmail()).one() != null) {
            return Result.error("邮箱已注册");
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", registerDTO.getUsername());
        User user = this.getOne(queryWrapper);
        if (user != null) {
            return Result.error("用户名已存在", 404);
        }
        String password = registerDTO.getPassword();
        if (password.length() < 8 || password.length() > 16) {
            return Result.error("密码长度8~16位", 404);
        }
        if (!Pattern.compile(REGEX).matcher(password).matches()) {
            return Result.error("密码需要同时包含数字、字母和特殊符号中的至少两种类型", 404);
        }
        if (!emailUtil.verifyCode(registerDTO.getEmail(), registerDTO.getCode())) {
            return Result.error("无效验证码", 404);
        }
        User user1 = BeanUtil.copyProperties(registerDTO, User.class);
        password = DigestUtils.md5DigestAsHex((SALT + user1.getPassword()).getBytes());
        user1.setPassword(password);
        this.save(user1);
        return Result.success(null, "用户注册成功");
    }

    /**
     * 重置密码
     * @param registerDTO
     * @return
     */
    @Override
    public Result<String> resetPassword(UserDTO registerDTO) {
        if (!FormatUtil.isEmail(registerDTO.getEmail())) {
            return Result.error("邮箱格式错误");
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", registerDTO.getId());
        User user = this.getOne(queryWrapper);
        String oldPassword = user.getPassword();
        String newPassword = registerDTO.getPassword();
        if (newPassword.length() < 8 || newPassword.length() > 16) {
            return Result.error("密码长度8~16位", 404);
        }
        if (!Pattern.compile(REGEX).matcher(newPassword).matches()) {
            return Result.error("密码需要同时包含数字、字母和特殊符号中的至少两种类型", 404);
        }
        System.out.println(newPassword);
        newPassword = DigestUtils.md5DigestAsHex((SALT + newPassword).getBytes());
        System.out.println(newPassword);
        if (newPassword.equals(oldPassword)) {
            return Result.error("更改密码不能与旧密码相同", 404);
        }
        if (!emailUtil.verifyCode(registerDTO.getEmail(), registerDTO.getCode())) {
            return Result.error("无效验证码", 404);
        }
        user.setPassword(newPassword);
        this.updateById(user);
        return Result.success(null, "密码更改成功");
    }

    /**
     * 获取用户信息
     * @return
     */
    @Override
    public Result<UserVO> getUserData() {
        Long userId = UserContext.getUserId();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", userId);
        User user = this.getOne(queryWrapper);
        Department department = departmentService.getById(user.getDepartmentId());
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        userVO.setDepartment(department.getName());
        userVO.setRole(user.getRole());
        return Result.success("用户信息查询成功", userVO);
    }

    @Override
    public Result<String> uploadFile(MultipartFile file) {
        try {
            String originalFilename = file.getOriginalFilename();
            String extension = null;
            if (originalFilename != null) {
                extension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            String objectName = UUID.randomUUID().toString() + extension;
            //文件请求路径
            String filePath = aliOssUtil.upload(file.getBytes(), objectName);
            return Result.success("文件上传成功", filePath);
        } catch (IOException e) {
            throw new UnauthorizedException("文件上传失败");
        }
    }
}
